<?php

// +----------------------------------------------------------------------
// |Author: 翼小菜
// +----------------------------------------------------------------------
// |Description: thinkcmf应用市场
// +----------------------------------------------------------------------
// |更多功能可联系QQ314688769
// +----------------------------------------------------------------------
namespace api\cveadmin\controller;
use cmf\controller\RestAdminBaseController;
use app\admin\logic\AppLogic;
use app\admin\logic\PluginLogic;
use app\admin\logic\ThemeLogic;
use app\admin\model\ThemeModel;
use cmf\model\OptionModel;
use think\facade\Db;

class AdminAppStoreController extends RestAdminBaseController
{
    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore",
     *     tags={"cveadmin"},
     *     summary="获取应用商店列表",
     *     description="获取应用商店的应用列表，包含安装状态和更新状态",
     *     @OA\Response(
     *         response=1,
     *         description="成功返回应用列表",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(
     *                 property="apps",
     *                 type="array",
     *                 @OA\Items(
     *                     type="object",
     *                     @OA\Property(property="name", type="string"),
     *                     @OA\Property(property="version", type="string"),
     *                     @OA\Property(property="installed", type="integer"),
     *                     @OA\Property(property="need_update", type="integer")
     *                 )
     *             ),
     *             @OA\Property(property="total", type="integer")
     *         )
     *     )
     * )
     */

    public function index()
    {
        $currentPage = $this->request->param('page', 1, 'intval');
        $url         = "https://www.thinkcmf.com/api/appstore/apps?{$this->buildRequestParams(['page'=>$currentPage])}";
        $data        = cmf_curl_get($url);

        $data = json_decode($data, true);
        $page = '';
        $total = 0;
        if (empty($data['code'])) {
            $apps = [];
        } else {
            $apps      = $data['data']['apps'];
            $total = $data['data']['total'];
        }

        $appstoreSettings = cmf_get_option('appstore_settings');
        $newApps = [];
        foreach ($apps as $mApp) {
            $mApp['installed']   = 0;
            $mApp['need_update'] = 0;
            $appName             = $mApp['name'];
            $findAppSetting      = OptionModel::where('option_name', "app_manifest_" . $appName)->find();

            if (!empty($findAppSetting)) {
                $installedApp          = $findAppSetting['option_value'];
                $mApp['installed']     = 1;
                if (version_compare($mApp['version'], $installedApp['version'], '>')) {
                    $mApp['need_update'] = 1;
                } else {
                    $mApp['need_update'] = 0;
                }
                $mApp['installed_app'] = $installedApp;
            }

            $newApps[] = $mApp;
        }
        $this->success('success', ['apps' => $newApps, 'total' => $total]);
    }

    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/plugins",
     *     summary="获取插件列表",
     *     tags={"cveadmin"},
     *     @OA\Response(
     *         response=200,
     *         description="成功返回插件列表",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=0),
     *             @OA\Property(property="msg", type="string", example="success"),
     *             @OA\Property(
     *                 property="data",
     *                 type="object",
     *                 @OA\Property(property="plugins", type="array",
     *                     @OA\Items(
     *                         @OA\Property(property="name", type="string"),
     *                         @OA\Property(property="version", type="string"),
     *                         @OA\Property(property="installed", type="integer"),
     *                         @OA\Property(property="need_update", type="integer"),
     *                         @OA\Property(property="installed_plugin", type="object", nullable=true)
     *                     )
     *                 ),
     *                 @OA\Property(property="total", type="integer")
     *             )
     *         )
     *     )
     * )
     */

    public function plugins()
    {
        $currentPage = $this->request->param('page', 1, 'intval');
        $url         = "https://www.thinkcmf.com/api/appstore/plugins?{$this->buildRequestParams(['page'=>$currentPage])}";
        $data        = cmf_curl_get($url);

        $data = json_decode($data, true);
        $page = '';
        $total = 0;
        if (empty($data['code'])) {
            $plugins = [];
        } else {
            $plugins   = $data['data']['plugins'];
            $total = $data['data']['total'];
        }

        $appstoreSettings = cmf_get_option('appstore_settings');

        $installedPlugins = Db::name('plugin')->column('*', 'name');

        $newPlugins = [];
        foreach ($plugins as $plugin) {
            $plugin['installed']   = 0;
            $plugin['need_update'] = 0;
            $pluginName            = cmf_parse_name($plugin['name'], 1);

            if (!empty($installedPlugins[$pluginName]) && is_dir(WEB_ROOT . 'plugins' . DIRECTORY_SEPARATOR . cmf_parse_name($plugin['name'], 0))) {
                $installedPlugin            = $installedPlugins[$pluginName];
                $plugin['installed']        = 1;
                if (version_compare($plugin['version'],$installedPlugin['version'], '>')) {
                    $plugin['need_update'] = 1;
                } else {
                    $plugin['need_update'] = 0;
                }
                $plugin['installed_plugin'] = $installedPlugin;
            }

            $newPlugins[] = $plugin;
        }


        $this->success('success', ['plugins' => $newPlugins, 'total' => $total]);
    }
    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/themes",
     *     tags={"cveadmin"},
     *     summary="获取主题列表",
     *     description="从应用商店获取主题列表信息",
     *     @OA\Response(
     *         response=200,
     *         description="成功返回主题列表",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="msg", type="string"),
     *             @OA\Property(
     *                 property="data",
     *                 type="object",
     *                 @OA\Property(property="themes", type="array", @OA\Items(
     *                     type="object",
     *                     @OA\Property(property="name", type="string"),
     *                     @OA\Property(property="version", type="string"),
     *                     @OA\Property(property="preview", type="string"),
     *                     @OA\Property(property="author", type="string"),
     *                     @OA\Property(property="author_url", type="string"),
     *                     @OA\Property(property="description", type="string"),
     *                     @OA\Property(property="installed", type="integer"),
     *                     @OA\Property(property="need_update", type="integer"),
     *                     @OA\Property(property="installed_theme", type="object", nullable=true)
     *                 )),
     *                 @OA\Property(property="total", type="integer")
     *             )
     *         )
     *     )
     * )
     */
    public function themes()
    {
        $currentPage = $this->request->param('page', 1, 'intval');
        $url         = "https://www.thinkcmf.com/api/appstore/themes?{$this->buildRequestParams(['page'=>$currentPage])}";
        $data        = cmf_curl_get($url);

        $data = json_decode($data, true);
        $page = '';
        $total = 0;
        if (empty($data['code'])) {
            $themes = [];
        } else {
            $themes    = $data['data']['themes'];
            $total = $data['data']['total'];
        }

        $appstoreSettings = cmf_get_option('appstore_settings');

        $newThemes = [];
        foreach ($themes as $mTheme) {
            $mTheme['installed']   = 0;
            $mTheme['need_update'] = 0;
            $themeName             = $mTheme['name'];
            if (strpos($themeName, 'admin_') !== 0) {
                $findTheme = ThemeModel::where('theme', $themeName)->find();
                if (!empty($findTheme)) {
                    $mTheme['installed']       = 1;
                    if (version_compare($mTheme['version'],$findTheme['version'],'>')) {
                        $mTheme['need_update'] = 1;
                    } else {
                        $mTheme['need_update'] = 0;
                    }
                    $mTheme['installed_theme'] = $findTheme;
                }
            } else {
                $optionName       = "theme_manifest_" . $themeName;
                $findThemeSetting = OptionModel::where('option_name', $optionName)->find();

                if (!empty($findThemeSetting)) {
                    $installedTheme            = $findThemeSetting['option_value'];
                    $mTheme['installed']       = 1;
                    if (version_compare($mTheme['version'],$installedTheme['version'],'>')) {
                        $mTheme['need_update'] = 1;
                    } else {
                        $mTheme['need_update'] = 0;
                    }
                    $mTheme['installed_theme'] = $installedTheme;
                }
            }

            $newThemes[] = $mTheme;
        }
        $this->success('success', ['themes' => $newThemes, 'total' => $total]);
    }
    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/install/app/{id}",
     *     summary="安装应用",
     *     tags={"cveadmin"},
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         required=true,
     *         description="应用ID",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Response(
     *         response=1,
     *         description="成功"
     *     )
     * )
     */
    public function installApp($id)
    {
        $dirs = [
            realpath(CMF_ROOT . 'api') . DIRECTORY_SEPARATOR,
            realpath(CMF_ROOT . 'app') . DIRECTORY_SEPARATOR,
            realpath(CMF_ROOT . 'data') . DIRECTORY_SEPARATOR,
            realpath(WEB_ROOT . 'plugins') . DIRECTORY_SEPARATOR,
            realpath(WEB_ROOT . 'themes') . DIRECTORY_SEPARATOR,
            realpath(WEB_ROOT . 'themes/admin_default') . DIRECTORY_SEPARATOR,
        ];

        foreach ($dirs as $dir) {
            if (!cmf_test_write($dir)) {
                $this->error('目录不可写' . $dir);
            }
        }

        $id      = $this->request->param('id', 0, 'intval');
        $version = $this->request->param('version', '');
        $data    = cmf_curl_get("https://www.thinkcmf.com/api/appstore/apps/{$id}?{$this->buildRequestParams(['version'=>$version])}");
        $data    = json_decode($data, true);

        if (empty($data['code'])) {
            if (!empty($data['data']['code']) && $data['data']['code'] == 10001) {
                cmf_set_option('appstore_settings', ['access_token' => '']);
                $this->error($data['msg'], null, ['code' => 10001]);
            }

            if (!empty($data['data']['code']) && $data['data']['code'] == 10002) {
                $this->error($data['msg'], null, ['code' => 10002]);
            }
        } else {
            $tmpFileName = "app{$id}_" . time() . microtime() . '.zip';

            $tmpFileDir = CMF_DATA . 'download/';

            if (!is_dir($tmpFileDir)) {
                mkdir($tmpFileDir, 0777, true);
            }

            $tmpFile = $tmpFileDir . $tmpFileName;
            $fp = fopen($tmpFile, 'wb') or $this->error('操作失败！'); //新建或打开文件,将curl下载的文件写入文件

            $ch = curl_init($data['data']['app']['download_url']);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
            $res = curl_exec($ch);
            curl_close($ch);
            fclose($fp);

            $appName = $data['data']['app']['name'];

            $archive = new \PclZip($tmpFile);
            $files = $archive->listContent();

            foreach ($files as $mFile) {
                $result = $archive->extractByIndex($mFile['index'], PCLZIP_OPT_PATH, CMF_ROOT, PCLZIP_OPT_REMOVE_PATH, "{$data['data']['app']['name']}/", PCLZIP_OPT_REPLACE_NEWER);
            }
            unlink($tmpFile);

            if (empty($version)) {
                $result = AppLogic::install($appName);
            } else {
                $result = AppLogic::update($appName);
            }

            if ($result !== true) {
                $this->error($result);
            }

        }
        if (empty($version)) {
            $this->success('安装成功');
        } else {
            $this->success('升级成功');
        }
    }

    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/install/plugin/{id}",
     *     tags={"cveadmin"},
     *     summary="安装插件",
     *     description="通过ID安装插件",
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         required=true,
     *         description="插件ID",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Parameter(
     *         name="version",
     *         in="query",
     *         required=false,
     *         description="版本号",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="成功响应",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=0),
     *             @OA\Property(property="msg", type="string", example="操作成功"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     ),
     *     @OA\Response(
     *         response=10001,
     *         description="Token无效",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=10001),
     *             @OA\Property(property="msg", type="string", example="Token无效"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     ),
     *     @OA\Response(
     *         response=10002,
     *         description="无权限",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=10002),
     *             @OA\Property(property="msg", type="string", example="无权限"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     )
     * )
     */

    public function installPlugin($id)
    {
        $id      = $this->request->param('id', 0, 'intval');
        $version = $this->request->param('version', '');
        $data    = cmf_curl_get("https://www.thinkcmf.com/api/appstore/plugins/{$id}?{$this->buildRequestParams(['version'=>$version])}");
        $data    = json_decode($data, true);

        if (empty($data['code'])) {
            if (!empty($data['data']['code']) && $data['data']['code'] == 10001) {
                cmf_set_option('appstore_settings', ['access_token' => '']);
                $this->error($data['msg'], null, ['code' => 10001]);
            }

            if (!empty($data['data']['code']) && $data['data']['code'] == 10002) {
                $this->error($data['msg'], null, ['code' => 10002]);
            }

        } else {
            $tmpFileName = "plugin{$id}_" . time() . microtime() . '.zip';

            $tmpFileDir = CMF_DATA . 'download/';

            if (!is_dir($tmpFileDir)) {
                mkdir($tmpFileDir, 0777, true);
            }

            $tmpFile = $tmpFileDir . $tmpFileName;
            $fp = fopen($tmpFile, 'wb') or $this->error('操作失败！'); //新建或打开文件,将curl下载的文件写入文件

            $ch = curl_init($data['data']['plugin']['download_url']);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
            $res = curl_exec($ch);
            curl_close($ch);
            fclose($fp);

            $pluginName = cmf_parse_name($data['data']['plugin']['name'], 0);

            $archive = new \PclZip($tmpFile);

            $files = $archive->listContent();


            foreach ($files as $mFile) {
                if (strpos($mFile['filename'], $pluginName) === 0) {
                    $result = $archive->extractByIndex($mFile['index'], PCLZIP_OPT_PATH, WEB_ROOT . 'plugins/', PCLZIP_OPT_REPLACE_NEWER);
                }
            }

            unlink($tmpFile);

            $pluginName = cmf_parse_name($pluginName, 1);

            if (empty($version)) {
                $result = PluginLogic::install($pluginName);
            } else {
                $result = PluginLogic::update($pluginName);
            }

            if ($result !== true) {
                $this->error($result);
            }

        }
        if (empty($version)) {
            $this->success('安装成功');
        } else {
            $this->success('升级成功');
        }
    }
    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/install/theme/{id}",
     *     tags={"cveadmin"},
     *     summary="安装模版",
     *     description="通过ID安装模版",
     *     @OA\Parameter(
     *         name="id",
     *         in="path",
     *         required=true,
     *         description="模版ID",
     *         @OA\Schema(type="integer")
     *     ),
     *     @OA\Parameter(
     *         name="version",
     *         in="query",
     *         required=false,
     *         description="版本号",
     *         @OA\Schema(type="string")
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="成功响应",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=0),
     *             @OA\Property(property="msg", type="string", example="操作成功"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     ),
     *     @OA\Response(
     *         response=10001,
     *         description="Token无效",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=10001),
     *             @OA\Property(property="msg", type="string", example="Token无效"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     ),
     *     @OA\Response(
     *         response=10002,
     *         description="无权限",
     *         @OA\JsonContent(
     *             @OA\Property(property="code", type="integer", example=10002),
     *             @OA\Property(property="msg", type="string", example="无权限"),
     *             @OA\Property(property="data", type="object")
     *         )
     *     )
     * )
     */
    public function installTheme($id)
    {
        $dirs = [
            realpath(CMF_ROOT . 'data') . DIRECTORY_SEPARATOR,
            realpath(WEB_ROOT . 'themes') . DIRECTORY_SEPARATOR,
        ];

        foreach ($dirs as $dir) {
            if (!cmf_test_write($dir)) {
                $this->error('目录不可写' . $dir);
            }
        }

        $id      = $this->request->param('id', 0, 'intval');
        $version = $this->request->param('version', '');
        $data    = cmf_curl_get("https://www.thinkcmf.com/api/appstore/themes/{$id}?{$this->buildRequestParams(['version'=>$version])}");
        $data    = json_decode($data, true);

        if (empty($data['code'])) {
            if (!empty($data['data']['code']) && $data['data']['code'] == 10001) {
                cmf_set_option('appstore_settings', ['access_token' => '']);
                $this->error($data['msg'], null, ['code' => 10001]);
            }

            if (!empty($data['data']['code']) && $data['data']['code'] == 10002) {
                $this->error($data['msg'], null, ['code' => 10002]);
            }
        } else {
            $tmpFileName = "theme{$id}_" . time() . microtime() . '.zip';

            $tmpFileDir = CMF_DATA . 'download/';

            if (!is_dir($tmpFileDir)) {
                mkdir($tmpFileDir, 0777, true);
            }

            $tmpFile = $tmpFileDir . $tmpFileName;
            $fp = fopen($tmpFile, 'wb') or $this->error('操作失败！'); //新建或打开文件,将curl下载的文件写入文件

            $ch = curl_init($data['data']['theme']['download_url']);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 信任任何证书
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 检查证书中是否设置域名
            $res = curl_exec($ch);
            curl_close($ch);
            fclose($fp);

            $themeName = $data['data']['theme']['name'];

            $archive = new \PclZip($tmpFile);

            $files = $archive->listContent();

            foreach ($files as $mFile) {
                $result = $archive->extractByIndex($mFile['index'], PCLZIP_OPT_PATH, WEB_ROOT . 'themes/', PCLZIP_OPT_REPLACE_NEWER);
            }

            unlink($tmpFile);

            if (empty($version)) {
                $result = ThemeLogic::install($themeName);
            } else {
                $result = ThemeLogic::update($themeName);
            }

            if ($result !== true) {
                $this->error($result);
            }

        }
        if (empty($version)) {
            $this->success('安装成功');
        } else {
            $this->success('升级成功');
        }
    }
    /**
     * @OA\Get(
     *     path="/cveadmin/admin_appstore/islogin",
     *     tags={"cveadmin"},
     *     summary="检测thinkCmf是否登陆",
     *     @OA\Response(response="200", description="返回登陆状态")
     * )
     */
    public function checkLogin()
    {
        $option = cmf_get_option('appstore_settings');
        if (empty($option)) {
            $this->error('请先登录');
        }else{
            $accessToken = $option['access_token'];
            $this->success('已登录', ['access_token' => $accessToken]);
        }
    }
    /**
     * @OA\Post(
     *     path="/cveadmin/admin_appstore/login",
     *     tags={"cveadmin"},
     *     summary="设置thinkCmf登录token",
     *     @OA\RequestBody(
     *         description="登录参数",
     *         required=true,
     *         @OA\JsonContent(
     *             required={"access_token"},
     *             @OA\Property(property="access_token", type="string", description="访问令牌")
     *         )
     *     ),
     *     @OA\Response(response="200", description="登录结果")
     * )
     */

    public function doLogin()
    {
        $params['access_token'] = $this->request->param('access_token','');
        if(empty($params['access_token'])){
            $this->error('参数错误');
        }
        cmf_set_option('appstore_settings', ['access_token' => $params['access_token']]);
        $this->success('登录成功');
        
    }

    private function buildRequestParams($params = [])
    {
        $appStoreSettings = cmf_get_option('appstore_settings');
        $accessToken      = '';
        if (!empty($appStoreSettings['access_token'])) {
            $accessToken = $appStoreSettings['access_token'];
        }

        $mysql = Db::query("select VERSION() as version");
        $mysql = $mysql[0]['version'];
        $mysql = empty($mysql) ? '' : $mysql;

        $httpReferer = $this->request->server('HTTP_REFERER');
        if (empty($httpReferer)) {
            $this->error(lang('illegal request'));
        }
        $httpReferer = parse_url($httpReferer);
        $domain      = empty($httpReferer['host']) ? '' : $httpReferer['host'];

        return http_build_query(array_merge([
            'token'  => $accessToken,
            'cmf'    => cmf_version(),
            'tp'     => cmf_thinkphp_version(),
            'php'    => phpversion(),
            'mysql'  => $mysql,
            'domain' => $domain,
        ], $params));
    }
}